// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License.  You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

// Wrapper for a fpnew
// Contributor: Davide Schiavone <davide@openhwgroup.org>

module cv32e40p_fp_wrapper import cv32e40p_apu_core_pkg::*; #(
  parameter FP_DIVSQRT = 0
)
(
  // Clock and Reset
  input  logic                                   clk_i,
  input  logic                                   rst_ni,

  // APU Side: Master port
  input  logic                                   apu_req_i,
  output logic                                   apu_gnt_o,

  // request channel
  input  logic [APU_NARGS_CPU-1:0][31:0]         apu_operands_i,
  input  logic [APU_WOP_CPU-1:0]                 apu_op_i,
  input  logic [APU_NDSFLAGS_CPU-1:0]            apu_flags_i,

  // response channel
  output logic                                   apu_rvalid_o,
  output logic [31:0]                            apu_rdata_o,
  output logic [APU_NUSFLAGS_CPU-1:0]            apu_rflags_o
);

  import cv32e40p_pkg::*;
  import fpnew_pkg::*;

  logic [fpnew_pkg::OP_BITS-1:0] fpu_op;
  logic                          fpu_op_mod;
  logic                          fpu_vec_op;

  logic [fpnew_pkg::FP_FORMAT_BITS-1:0]  fpu_dst_fmt;
  logic [fpnew_pkg::FP_FORMAT_BITS-1:0]  fpu_src_fmt;
  logic [fpnew_pkg::INT_FORMAT_BITS-1:0] fpu_int_fmt;
  logic [C_RM-1:0]                       fp_rnd_mode;

  // assign apu_rID_o = '0;
  assign {fpu_vec_op, fpu_op_mod, fpu_op}                     = apu_op_i;

  assign {fpu_int_fmt, fpu_src_fmt, fpu_dst_fmt, fp_rnd_mode} = apu_flags_i;

  localparam fpnew_pkg::unit_type_t C_DIV = FP_DIVSQRT ? fpnew_pkg::MERGED : fpnew_pkg::DISABLED;

  // -----------
  // FPU Config
  // -----------
  // Features (enabled formats, vectors etc.)
  localparam fpnew_pkg::fpu_features_t FPU_FEATURES = '{
    Width:         C_FLEN,
    EnableVectors: C_XFVEC,
    EnableNanBox:  1'b0,
    FpFmtMask:     {C_RVF, C_RVD, C_XF16, C_XF8, C_XF16ALT, C_XF8ALT},
    IntFmtMask:    {C_XFVEC && (C_XF8 || C_XF8ALT), C_XFVEC && (C_XF16 || C_XF16ALT), 1'b1, 1'b0}
  };

  // Implementation (number of registers etc)
  localparam fpnew_pkg::fpu_implementation_t FPU_IMPLEMENTATION = '{
    PipeRegs:  '{// FP32, FP64, FP16, FP8, FP16alt
          '{C_LAT_FP32, C_LAT_FP64, C_LAT_FP16, C_LAT_FP8, C_LAT_FP16ALT, C_LAT_FP8ALT}, // ADDMUL
          '{default: C_LAT_DIVSQRT}, // DIVSQRT
          '{default: C_LAT_NONCOMP}, // NONCOMP
          '{default: C_LAT_CONV},    // CONV
          '{default: C_LAT_DOTP}},   // DOTP
    UnitTypes: '{'{default: fpnew_pkg::MERGED},   // ADDMUL
          '{default: C_DIV},   // DIVSQRT
          '{default: fpnew_pkg::PARALLEL}, // NONCOMP
          '{default: fpnew_pkg::MERGED},   // CONV
          '{default: fpnew_pkg::DISABLED}}, // DOTP
    PipeConfig: fpnew_pkg::AFTER
  };

  //---------------
  // FPU instance
  //---------------

  fpnew_top #(
    .Features                    ( FPU_FEATURES              ),
    .Implementation              ( FPU_IMPLEMENTATION        ),
    .TagType                     ( logic                     ),
    .PulpDivsqrt                 ( 1'b0                      ),
    .TrueSIMDClass               ( 1'b0                      ),
    .EnableSIMDMask              ( 1'b0                      ),
    .CompressedVecCmpResult      ( 1'b0                      ),
    .StochasticRndImplementation ( fpnew_pkg::DEFAULT_NO_RSR )
  ) i_fpnew_bulk (
    .clk_i          ( clk_i                                 ),
    .rst_ni         ( rst_ni                                ),
    .hart_id_i      ( '0                                    ),
    .operands_i     ( apu_operands_i                        ),
    .rnd_mode_i     ( fpnew_pkg::roundmode_e'(fp_rnd_mode)  ),
    .op_i           ( fpnew_pkg::operation_e'(fpu_op)       ),
    .op_mod_i       ( fpu_op_mod                            ),
    .src_fmt_i      ( fpnew_pkg::fp_format_e'(fpu_src_fmt)  ),
    .dst_fmt_i      ( fpnew_pkg::fp_format_e'(fpu_dst_fmt)  ),
    .int_fmt_i      ( fpnew_pkg::int_format_e'(fpu_int_fmt) ),
    .vectorial_op_i ( fpu_vec_op                            ),
    .tag_i          ( 1'b0                                  ),
    .simd_mask_i    ( '1                                    ),
    .in_valid_i     ( apu_req_i                             ),
    .in_ready_o     ( apu_gnt_o                             ),
    .flush_i        ( 1'b0                                  ),
    .result_o       ( apu_rdata_o                           ),
    .status_o       ( apu_rflags_o                          ),
    .tag_o          ( /* unused */                          ),
    .out_valid_o    ( apu_rvalid_o                          ),
    .out_ready_i    ( 1'b1                                  ),
    .busy_o         ( /* unused */                          )
  );

endmodule // cv32e40p_fp_wrapper
